// factory - creating elements
//
// 'iterator' : { [ 'from':0, 'thru':9'[, 'inc':1] | 'set':<object or array> ], 'function' : function(i,v) { ...; return element or something } }

Element.prototype.appendE = function() {
	// create fragment using arguments, append that onto element
	this.appendChild( E.f( {'callee':this}, (Array.prototype.slice.call(arguments)) ) );
	return this;
}

Element.prototype.replaceE = function() {
	// remove children; create fragment using arguments, append that onto element
	while( this.lastChild ) this.removeChild( this.lastChild );
	this.appendChild( E.f( {'callee':this}, (Array.prototype.slice.call(arguments)) ) );
	return this;
}

// make easy to create element via html
var E = {

'E': function( tag ) {
	// element itself
	//-console.log( 'E.'+tag+' - - - - - -' );
	var element = (tag=='fragment') ? document.createDocumentFragment() : document.createElement(tag);
	var callee = element;
	for( var i=1; i<arguments.length; i++ ) addElement(arguments[i]);
	//-console.log( '- - - - return E.'+tag+': '+element );
	return element;

	function addElement( arg ) {

		//-console.log( tag+' addElement: '+arg );

		// if null, ignore
		if( arg === null ) return;

		// if fragment, append
		else if( arg instanceof DocumentFragment ) {
			element.appendChild( arg );
		}

		// array - recur
		else if( arg instanceof Array ) {
			//-console.log( tag+' adding array: '+arg );
			for( var j=0; j<arg.length; j++ )  addElement(arg[j]);
		}

		// if ol or ul, make object into li
		else if( ( tag == 'ol' || tag == 'ul' ) && typeof arg == 'object' ) {
			//-console.log( "ul object: "+arg );
			if( arg instanceof HTMLLIElement )	element.appendChild( arg );
			else					element.appendChild( E.li( arg ) );
		}

		// non-object - deal with it a text
		else if( typeof arg != 'object' ) {

			//-console.log( 'tag='+tag+', text: ' + arg );

			// specialty: id, className, quote
			if( typeof arg == 'number' ) {
				if( tag!='input' || tag!='textarea' )	element.value = arg
				else					element.appendChild( document.createTextNode(arg) );
			}
			else if( arg.substr(0,1)=='`' )			element.appendChild( document.createTextNode(arg.substr(1)) );
			else if( arg.substr(0,1)=='#' )			callee.id = arg.substr(1);
			else if( arg.substr(0,1)==':' )			callee.setAttribute( 'name', arg.substr(1) );
			else if( arg.substr(0,1)=='.' )			callee.className = arg.substr(1);
			else if( arg.substr(0,1)=='=' )			callee.value = arg.substr(1);
			else if( match_arr = arg.match(/a\.(.+):(.*)/))	callee.setAttribute(match_arr[1],match_arr[2]);
			else if( match_arr = arg.match(/e\.(.+):(.*)/))	callee.AddEventListener(match_arr[1],match_arr[2]);
			else if( match_arr = arg.match(/s\.(.+):(.*)/))	callee.style[match_arr[1]] = match_arr[2];
			else if( match_arr = arg.match(/o\.(.+):(.*)/))	callee.appendChild( E.option(match_arr[1],match_arr[2],{'checked':match_arr[1]==this.value}) );
			else if( tag=='input' || tag=='textarea' )	element.value = arg;
			else if( tag == 'select' )			element.appendChild( E.option( arg, arg, {'checked':arg==this.value} ) );
			else if( tag == 'ol' || tag == 'ul' )		element.appendChild( E.li( arg ) );
			else						element.appendChild( document.createTextNode(arg) );
		}
		
		// html element - append
		else if( arg instanceof Element ) {
			//-console.log( 'element: ' + arg );
			element.appendChild( arg );
		}
		
		// non-html object
		else {
			//-console.log( 'attributes in object  - - - -' );
			for( var attr in arg ) if( typeof attr == 'string' ) {

				var match_arr;
				// iterator
				if( attr == 'iterator' ) {
					// from - thru iterator - whether or not operating on an object/array
					if( arg[attr].from!=undefined && arg[attr].thru!=undefined && arg[attr].set==undefined ) {
						var inc = (arg[attr].inc != undefined ) ? arg[attr].inc : ((arg[attr].from<=arg[attr].thru)?1:-1);
						for( var i = arg[attr].from; i<=arg[attr].thru; i+=inc ) {
							if( arg[attr].set == undefined ) addElement( (arg[attr]['function'])(i) );
							else				 addElement( (arg[attr]['function'])(i,arg[attr][i]) );
						}
					}
					// operating on an object/array with length property
					else if( arg[attr].set.length != undefined ) {
						for( var i = 0; i<arg[attr].set.length; i++ ) {
							addElement( (arg[attr]['function'])(i,arg[attr][i]) );
						}
					}
					// elements in an object without a length property
					else if( arg[attr].set ) {
						for( var i in arg[attr].set ) if( typeof i != 'function' ) {
							addElement( (arg[attr]['function'])(i,arg[attr].set[i]) );
						}
					}
				}
				// text
				if( attr == 'text' ) {
					element.appendChild( document.createTextNode(arg[attr]) );
				}
				// style
				else if( match_arr = attr.match(/^(style|s)\.(.*)/ ) ) {
					callee.style[match_arr[2]] = arg[attr];
				}
				// event
				else if( match_arr = attr.match(/^(event|e)\.(.*)/) ) {
					if( arg[attr] ) callee.addEventListener(match_arr[2],arg[attr],true);
				}
				// attributes
				else if( match_arr = attr.match(/^(attribute|a)\.(.*)/) ) {
					callee.setAttribute( match_arr[2], arg[attr] );

				}
				// select option
				else if( tag == 'select' && (match_arr = attr.match(/^(option|o)\.(.*)/)) ) {
					addOption( match_arr[2], arg[attr] );
				}
				// checked value
				else if( attr == 'set_value' ) {
					callee.checked = (callee.value == arg[attr] );
				}
				// select value
				else if( tag == 'select' && attr == 'value' ) {
					var value = arg[attr];
				}
				// callee
				else if( attr == 'callee' ) {
					callee = arg[attr];
					//-console.log( 'callee set to '+arg[attr] );
				}
				// properties
				else	callee[attr] = arg[attr];
			}
		}

		// append option onto select - var value must have been set in order for option to be checked
		function addOption( val, str ) {
			var opt = document.createElement('option');
			opt.value = val;
			opt.appendChild( document.createTextNode( str ) );
			opt.checked = ( value != undefined && val == value );
			element.appendChild( opt );
		}
	}
},

// set( {defaults}, E.tag( locals ), ... ) === E.tag( locals, {defaults} ), ...
// note!! default values overwrite local values!!
'defaults': function(  ) {
	var args = Array.prototype.slice.call(arguments);
	var dflt = args.shift();
	var f = E.f();
	//-Array.forEach( arguments, function(e) { 
	args.forEach( function(e) { 
			//-console.log( 'scoper: e='+e+', HTMLElement='+(e instanceof HTMLElement )+', dflt='+dflt );
			if( e instanceof HTMLElement ) e.appendE( dflt );
			else if( e instanceof DocumentFragment ) null;
			else e = document.createTextNode(e);
			//-console.log( 'result='+e );
			f.appendChild( e );
		} );
	//-console.log( 'return: '+f+' - '+f.childNodes.length );
	//-for( var i=0; i<f.childNodes.length; i++ ) console.log( 'child: '+f.childNodes[i] );
	return f;
},
// TR: [class] attrs elements or innerHTML
'div': function() { return E.E('div',Array.prototype.slice.call(arguments)) },
'span': function() { return E.E('span',Array.prototype.slice.call(arguments)) },
'f': function() { return E.E('fragment',Array.prototype.slice.call(arguments)) },
'table': function() { return E.E('table',Array.prototype.slice.call(arguments)) },
'tr': function() { return E.E('tr',Array.prototype.slice.call(arguments)) },
'td': function() { return E.E('td',Array.prototype.slice.call(arguments)) },
'th': function() { return E.E('th',Array.prototype.slice.call(arguments)) },
'button': function( click ) { return E.E( 'button', {'event.click':click}, Array.prototype.slice.call(arguments,1) ); },
'a': function( href, click ) { 
	return E.E( 'a', {'href':href,'event.click':click}, Array.prototype.slice.call(arguments,2) );
},

'form': function() { return E.E('form',Array.prototype.slice.call(arguments)) },
'input': function() { return E.E('input',{'type':'text'},Array.prototype.slice.call(arguments)) },
'password': function() { return E.E('input',{'type':'password'},Array.prototype.slice.call(arguments)) },
'hidden': function() { return E.E('input',{'type':'hidden'},Array.prototype.slice.call(arguments)) },
'checkbox': function() { return E.E('input',{'type':'checkbox'},Array.prototype.slice.call(arguments)) },
'textarea': function() { return E.E('textarea',Array.prototype.slice.call(arguments)) },
'radio': function() { return E.E('input',{'type':'radio'},Array.prototype.slice.call(arguments)) },
'select': function() { return E.E('select',Array.prototype.slice.call(arguments)) },
'option': function() { return E.E('option',Array.prototype.slice.call(arguments)) },

'i': function() { return E.E('i',Array.prototype.slice.call(arguments)) },
'b': function() { return E.E('b',Array.prototype.slice.call(arguments)) },
's': function() { return E.E('s',Array.prototype.slice.call(arguments)) },
'code': function() { return E.E('code',Array.prototype.slice.call(arguments)) },

'ul': function() { return E.E('ul',Array.prototype.slice.call(arguments)) },
'ol': function() { return E.E('ol',Array.prototype.slice.call(arguments)) },
'li': function() { return E.E('li',Array.prototype.slice.call(arguments)) },

'h1': function() { return E.E('h1',Array.prototype.slice.call(arguments)) },
'h2': function() { return E.E('h2',Array.prototype.slice.call(arguments)) },
'h3': function() { return E.E('h3',Array.prototype.slice.call(arguments)) },
'h4': function() { return E.E('h4',Array.prototype.slice.call(arguments)) },

'br': function() { return E.E('br',Array.prototype.slice.call(arguments)) },
'hr': function() { return E.E('hr',Array.prototype.slice.call(arguments)) },

'text': function() { return document.createTextNode( Array.prototype.slice.call(arguments).join(' ') ) }

}
